/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.amse.grigory.dchess.player;

import java.util.TreeMap;
import org.amse.grigory.dchess.kernel.*;
import org.amse.grigory.dchess.rules.Rules;

/**
 *
 * @author grigory
 */
public class AIPlayer implements IPlayer {

    public final static int RANDOM = 0;
    public final static int EASY = 2;
    private Object myLock;
    private int myX = -1,  myY = -1,  mySX = -1,  mySY = -1;
    private int myLevel;
    private IModel myModel;
    private boolean myMoved;
    private int myColor;
    
    private double myValue;

    public AIPlayer(int level, IModel model) {
        myLock = new Object();
        myLevel = level;
        if (myLevel < 0) {
            myLevel = 0;
        }
        myModel = model;
    }

    public void stop() {
        
    }

    public void calc() {
        myMoved = false;
        new calcThread().start();
    }

    public Object lock() {
        return myLock;
    }

    public int getX() {
        return myX;
    }

    public int getY() {
        return myY;
    }

    public int getSX() {
        return mySX;
    }

    public int getSY() {
        return mySY;
    }

    private final void randomMove() {
        int x, y, sx, sy;
        while (true) {
            x = (int) (Math.random() * myModel.getHeight() + 1);
            y = (int) (Math.random() * myModel.getWidth() + 1);
            sx = (int) (Math.random() * myModel.getHeight() + 1);
            sy = (int) (Math.random() * myModel.getWidth() + 1);
            if (myModel.canMove(sx, sy, x, y)) {
                break;
            }
        }
        myX = x;
        myY = y;
        mySX = sx;
        mySY = sy;

    }
    //------------------------------
    private void countMove() {
        Desk desk=myModel.getDeskClone();
        myValue=positionCost(desk);
        countDFS(desk, myLevel);
    }

    private double countDFS(Desk desk, int depth) {
        if (depth==0){
            return positionCost(desk);
        }
        double res=positionCost(desk);
        double val;
        if (myValue<0){
            val=myValue-1;
        }else{
            val=myValue-1;
        }
        if ((val>res)){
            return res;
        }
        int n;
        int parity=(myLevel-depth) % 2;
        if ((myColor == Rules.COLOR_BLACK)^(parity==1)) {
            n = desk.getBlackCount();
        } else {
            n = desk.getWhiteCount();
        }
        double result;        
        if ( parity == 0) {
            result = -Double.MAX_VALUE;
        } else {
            result = Double.MAX_VALUE;
        }
        for (int i = 0; i < n; i++) {
            Figure temp;
            if ((myColor == Rules.COLOR_BLACK)^(parity==1)) {
                temp = desk.getBlackFigure(i);
            } else {
                /*System.out.println("---");
                System.out.println("myColor="+myColor+" parity="+parity);
                System.out.println("n="+n+" i="+i+" white="+desk.getWhiteCount());*/
                temp = desk.getWhiteFigure(i);                
            } 
            for (int j=0; j<temp.getMovesCount(); j++){
                int x=temp.getX();
                int y=temp.getY();
                int ex=x+temp.getMoveX(j);
                int ey=y+temp.getMoveY(j);
                if (desk.canMove(x,y,ex,ey)){
                    //Desk tempDesk=desk.clone();
                    //tempDesk.makeMove(x, y, ex, ey);
                    desk.makeMove(x, y, ex, ey);
                    double value=countDFS(desk,depth-1);
                    desk.undo();
                    if (parity == 0){
                        if (value>result){
                            result=value;
                            if (depth == myLevel){
                                myX=ex;
                                myY=ey;
                                mySX=x;
                                mySY=y;
                            }
                        }
                        
                    }else{
                        if (value<result){
                            result=value;                            
                        }                        
                    }                    
                }
            }
            for (int j=0; j<temp.getEatCount(); j++){
                int x=temp.getX();
                int y=temp.getY();
                int ex=x+temp.getEatX(j);
                int ey=y+temp.getEatY(j);
                if (desk.canMove(x,y,ex,ey)){
                    //Desk tempDesk=desk.clone();
                    //tempDesk.makeMove(x, y, ex, ey);
                    desk.makeMove(x, y, ex, ey);
                    double value=countDFS(desk,depth-1);
                    desk.undo();
                    if (parity == 0){
                        if (value>result){
                            result=value;
                            if (depth == myLevel){
                                myX=ex;
                                myY=ey;
                                mySX=x;
                                mySY=y;
                            }
                        }
                        
                    }else{
                        if (value<result){
                            result=value;                            
                        }                        
                    }
                    
                }
            }
            
        }
        return result;
    }
    /*private void countMove() {
    int h = myModel.getHeight();
    int w = myModel.getWidth();
    double max = -10000;
    for (int sx = 0; sx < h; sx++) {
    for (int sy = 0; sy < h; sy++) {
    for (int x = 0; x < h; x++) {
    for (int y = 0; y < h; y++) {
    if (myModel.canMove(sx + 1, sy + 1, x + 1, y + 1)) {
    Desk temp = myModel.getDeskClone();
    if (temp.makeMove(sx + 1, sy + 1, x + 1, y + 1)) {
    double curr = countDFS(temp, myLevel - 1);
    if (curr > max) {
    max = curr;
    mySX = sx + 1;
    mySY = sy + 1;
    myX = x + 1;
    myY = y + 1;
    }
    
    }
    }
    }
    }
    
    }
    }
    }
    
    private double countDFS(Desk desk, int depth) {
    
    if (depth == 0) {
    return positionCost(desk);
    } else {            
    int h = myModel.getHeight();
    int w = myModel.getWidth();
    if ((myLevel - depth) % 2 == 1) {
    double min = Double.MAX_VALUE;
    for (int sx = 0; sx < h; sx++) {
    for (int sy = 0; sy < h; sy++) {
    for (int x = 0; x < h; x++) {
    for (int y = 0; y < h; y++) {
    if (desk.canMove(sx + 1, sy + 1, x + 1, y + 1)) {
    Desk temp = desk.clone();                                    
    if (temp.makeMove(sx + 1, sy + 1, x + 1, y + 1)) {                                      
    double curr = countDFS(temp, depth - 1);
    if (curr < min) {
    min = curr;
    }
    
    }
    }
    }
    }
    
    }
    }
    if (min==Double.MAX_VALUE){                    
    return positionCost(desk);
    }
    return min;
    
    } else {
    double max = Double.MIN_VALUE;
    for (int sx = 0; sx < h; sx++) {
    for (int sy = 0; sy < h; sy++) {
    for (int x = 0; x < h; x++) {
    for (int y = 0; y < h; y++) {
    if (desk.canMove(sx + 1, sy + 1, x + 1, y + 1)) {
    Desk temp = desk.clone();
    if (temp.makeMove(sx + 1, sy + 1, x + 1, y + 1)) {
    double curr = countDFS(temp, depth - 1);
    if (curr < max) {
    max = curr;
    }
    
    }
    }
    }
    }
    
    }
    }
    if (max==Double.MIN_VALUE){
    return positionCost(desk);
    }
    return max;
    }
    
    }
    
    }*/

    //-------------------
    private double positionCost(Desk temp) {
        int isWin = temp.isWin();
        //System.out.println(temp);
        if (isWin == Rules.NOBODY_WIN) {
            double sum = 0;
            for (int i = 0; i < myModel.getWidth(); ++i) {
                for (int j = 0; j < myModel.getHeight(); ++j) {
                    if (temp.getFigureName(i, j) != null) {
                        if (temp.getFigureColor(i, j) == myColor) {
                            sum += figureCost(temp.getFigureName(i, j)) * squareCost(i, j, temp.getFigureName(i, j), temp.getFigureColor(i, j));
                        } else {
                            sum -= figureCost(temp.getFigureName(i, j)) * squareCost(i, j, temp.getFigureName(i, j), temp.getFigureColor(i, j));
                        }
                    }


                }
            }

            return sum;
        } else {
            if (isWin == Rules.BLACK_WIN) {
                if (myColor == Rules.COLOR_BLACK) {
                    return Double.MAX_VALUE / 2;
                }
                if (myColor == Rules.COLOR_WHITE) {
                    return -Double.MAX_VALUE / 2;
                }
            }
            if (isWin == Rules.WHITE_WIN) {
                if (myColor == Rules.COLOR_BLACK) {
                    return -Double.MAX_VALUE / 2;
                }
                if (myColor == Rules.COLOR_WHITE) {
                    return Double.MAX_VALUE / 2;
                }
            }

        }
        return 0;
    }

    private double squareCost(int x, int y, String s, int color) {
        int w = myModel.getWidth();
        int h = myModel.getHeight();
        if (s.equals("Pawn")) {
            if (myColor == Rules.COLOR_WHITE) {
                return 1 + 0.01 * Math.abs(y*y) * (1 + w / 2 - Math.abs(x - 0.5 - w / 2));
            } else {
                return 1 + 0.01 * Math.abs((h - y)*(h-y)) * (1 + w / 2 - Math.abs(x - 0.5 - w / 2));
            }

        } else {
            return 1;
        }
    }

    private int figureCost(String s) {
        if (s.equals("Pawn")) {
            return 1;
        }
        if (s.equals("Knight")) {
            return 3;
        }
        if (s.equals("Bishop")) {
            return 3;
        }
        if (s.equals("Rook")) {
            return 5;
        }
        if (s.equals("Queen")) {
            return 9;
        }
        if (s.equals("Marshal")) {
            return 9;
        }
        if (s.equals("Cardinal")) {
            return 5;
        }
        if (s.equals("Champion")) {
            return 4;
        }
        if (s.equals("Wizard")) {
            return 3;
        }
        return 0;
    }

    private class calcThread extends Thread {

        @Override
        public void run() {
            if (myLevel == RANDOM) {
                randomMove();
            } else {
                countMove();
            }
            synchronized (myLock) {
                myMoved = true;
                myLock.notify();
            }
        }
    }

    public boolean moved() {
        return myMoved;
    }

    public int getColor() {
        return myColor;
    }

    public void setColor(int color) {
        myColor = color;
    }
}
